function 删除所有飘窗() {
	var 飘窗表 = document.getElementsByClassName('zhxd-piao');
	if (飘窗表.length !== 0)
		飘窗表[0].parentNode.removeChild(飘窗表[0]); 
}

function 解析制表符分隔文件(数据) {
	var 转入表 = this.转入表 = {}, 转出表 = this.转出表 = {};
	var 是转出 = this.是转出;
	数据.split('\n').forEach(行 => {
		var 表 = 行.split('\t', 3);
		var 希顶写法 = 表[是转出 ? 1 : 0], 现写法 = 表[是转出 ? 0 : 1];
		var 注 = 表[2];
		if (!希顶写法 || !现写法)
			return;

		if (!转入表[希顶写法])
			转入表[希顶写法] = [];
		转入表[希顶写法].push([ 现写法, 注 ]);
		if (!转出表[现写法])
			转出表[现写法] = [];
		转出表[现写法].push([ 希顶写法, 注 ]);
	});
}

var 词尾标点正则 = /[。？！，、；：“”‘'（）《》〈〉【】『』「」﹃﹄〔〕…—～﹏￥,\.\/<>\?;:"\[\]\\\{\}\|`\-=~!@#\$%\^\&\*\(\)_\+]$/;

var 传统缓存 = {};

function 传统(词, 表) {
	if (!词)		return [ [] ];
	if (传统缓存[词])	return 传统缓存[词];
	var 结果 = [];
	for (var i in 词) {
		var 右词 = 词.slice(i);
		var 右表 = 表[右词];
		if (右表) 传统(词.slice(0, i), 表).forEach(左 => {
			右表.forEach(右 => 结果.push(
				左.concat([ [ 右词 ].concat(右) ]))); });
	}
	var 词尾标点位置 = 词.search(词尾标点正则);
	if (-1 != 词尾标点位置 && !表[词.slice(词尾标点位置)]) {
		var 词尾标点 = 词.slice(词尾标点位置);
		传统(词.slice(0, i), 表).forEach(左 => 结果.push(
			左.concat([ [ 词尾标点, 词尾标点 ] ])));
	}
	return 传统缓存[词] = 结果;
}

function 传统转出(词) { 传统缓存 = {}; return 传统(词, this.转出表); }
function 传统转入(词) { 传统缓存 = {}; return 传统(词, this.转入表); }

function 传统严格(词, 表) {
	if (!词)		return [ [] ];
	if (传统缓存[词])	return 传统缓存[词];
	var 结果 = [];
	for (var i in 词) {
		var 右词 = 词.slice(i);
		var 右表 = 表[右词];
		if (右表 && 右表.length != 0) {
			var 左表 = 传统(词.slice(0, i), 表);
			if (左表 && 左表.length != 0) {
				var 左 = 左表[0], 右 = 右表[0];
				结果.push(左.concat([ [ 右词 ].concat(右) ]));
				break;
			}
		}
	}
	if (结果.length != 0)
		return 传统缓存[词] = 结果;
	var 词尾标点位置 = 词.search(词尾标点正则);
	if (-1 != 词尾标点位置 && !表[词.slice(词尾标点位置)]) {
		var 词尾标点 = 词.slice(词尾标点位置);
		var 左表 = 传统(词.slice(0, i), 表);
		if (左表 && 左表.length != 0)
			结果.push(左表[0].concat([ [ 词尾标点, 词尾标点 ] ]));
	}
	return 传统缓存[词] = 结果;
}

function 传统严格转出(词) { 传统缓存 = {}; return 传统严格(词, this.转出表); }
function 传统严格转入(词) { 传统缓存 = {}; return 传统严格(词, this.转入表); }

function 空转(原文) {
	return [ 原文.split('').map(x => [ x, x ]) ];
}

function 简单转换(表, 词) {
	return [ 词.split('').map(x => [ x ].concat(表[x] ? 表[x][0] : x)) ];
}

function 简易转出(词) { return 简单转换(this.转出表, 词); }
function 简易转入(词) { return 简单转换(this.转入表, 词); }

var 是声母 = {
	'b': true, 'p': true, 'm': true, 'f': true, 'w': true, 'j': true,
	'q': true, 'x': true, 'y': true, 'n': true, 'z': true, 'D': true,
	'H': true, 's': true, 'r': true, 'd': true, 't': true, 'l': true,
	'g': true, 'k': true, 'N': true, 'h': true, '4': true, 'F': true,
	'7': true, 'B': true, 'c': true, '5': true, 'v': true
};

var 是韵母 = {
	'E': true, 'a': true, 'o': true, 'e': true, '1': true, 'A': true,
	'Y': true, 'L': true, 'V': true, '6': true, '2': true, 'T': true,
	'8': true, '3': true
}

var 是介母 = { 'i': true, 'u': true };

function 表情转换(表, 词) {
	var 结果 = [], 前声母 = null, 前介母 = null, 前韵母 = null;
	function 加(字, 位) {
		结果.push([ 字 ].concat(表[字][位]));
	}
	function 成音节() {
		if (!前声母 || !前韵母)
			return false;
		加(前声母, 1);
		if (前介母)
			加(前介母, 1);
		加(前韵母, 1);
		前声母 = 前介母 = 前韵母 = null;
		return true;
	}
	词.split('').forEach(字 => {
		if (是声母[字]) {
			if (前声母)	{ 加(前声母, 0); 前声母 = null; }
			if (前介母)	{ 加(前介母, 0); 前介母 = null; }
			if (前韵母)	{ 加(前韵母, 0); 前韵母 = null; }
			前声母 = 字;
		} else if (是介母[字]) { 
			if (前介母)	{ 加(前介母, 0); 前介母 = null; }
			if (前韵母)	{ 加(前韵母, 0); 前韵母 = null; }
			前介母 = 字;
		} else if (是韵母[字]) {
			if (前韵母)	{ 加(前韵母, 0); 前韵母 = null; }
			前韵母 = 字;
		} else {
			if (前声母)	{ 加(前声母, 0); 前声母 = null; }
			if (前介母)	{ 加(前介母, 0); 前介母 = null; }
			if (前韵母)	{ 加(前韵母, 0); 前韵母 = null; }
			结果.push([ 字, 字 ]);
		}
		成音节();
	});
	if (前声母)	加(前声母, 0);
	if (前介母)	加(前介母, 0);
	if (前韵母)	加(前韵母, 0);
	return [ 结果 ];
}

function 表情转入(词) { return 表情转换(this.转入表, 词); }

var 文字表 = [
	{ 名: '希顶字母', 转出操作: 空转, 转入操作: 空转 },
	{ 名: '汉字', 键: 'hanzi2xdi8', 读表: 解析制表符分隔文件, 是转出: true, 转出操作: 传统转出, 转入操作: 传统转入 },
	{ 名: '汉字（希顶汉语）', 键: 'hanzi2xdhan', 读表: 解析制表符分隔文件, 是转出: true, 转出操作: 传统转出, 转入操作: 传统转入 },
	{ 名: '汉字（西丁语）', 键: 'oldxdi8', 读表: 解析制表符分隔文件, 是转出: false, 转出操作: 传统转出, 转入操作: 传统转入 },
	{ 名: '希顶字母（私用区）', 键: 'pua2xdi8', 读表: 解析制表符分隔文件, 是转出: true, 转出操作: 简易转出, 转入操作: 简易转入 },
	{ 名: '形近替代字', 键: 'tidai2xdi8', 读表: 解析制表符分隔文件, 是转出: true, 转出操作: 简易转出 }, 
	{ 名: '形近替代字', 键: 'xdi82tidai', 读表: 解析制表符分隔文件, 是转出: false, 转入操作: 简易转入 }, 
	{ 名: '国际音标', 键: 'xdi82ipa', 读表: 解析制表符分隔文件, 是转出: false, 转出操作: 传统转出, 转入操作: 传统严格转入 },
	{ 名: '汉写体', 键: 'xdi82hanxie', 读表: 解析制表符分隔文件, 是转出: false, 转出操作: 简易转出, 转入操作: 简易转入 },
	{ 名: '汉语拼音', 键: 'xdi82pinyin', 读表: 解析制表符分隔文件, 是转出: false, 转出操作: 传统转出, 转入操作: 传统严格转入 },
	{ 名: '假名', 键: 'xdi82kana', 读表: 解析制表符分隔文件, 是转出: false, 转出操作: 传统转出, 转入操作: 传统严格转入 },
	{ 名: '电码', 键: 'xdi82morse', 读表: 解析制表符分隔文件, 是转出: false, 转出操作: 传统转出, 转入操作: 简易转入 }, 
	{ 名: '注音符号', 键: 'xdi82zhuyin', 读表: 解析制表符分隔文件, 是转出: false, 转出操作: 简易转出, 转入操作: 简易转入 }, 
	{ 名: '浅夏青柠拉丁化', 键: 'xdi82latin', 读表: 解析制表符分隔文件, 是转出: false, 转出操作: 传统转出, 转入操作: 传统严格转入 },
	{ 名: '西里尔字母', 键: 'xdi82cyr', 读表: 解析制表符分隔文件, 是转出: false, 转出操作: 传统转出, 转入操作: 传统严格转入 },
	{ 名: '阿拉伯字母', 键: 'xdi82ar', 读表: 解析制表符分隔文件, 是转出: false, 转出操作: 传统转出, 转入操作: 传统严格转入 },
	{ 名: '希北古典字母', 键: 'xdi82gudian', 读表: 解析制表符分隔文件, 是转出: false, 转出操作: 简易转出, 转入操作: 简易转入 },
	{ 名: '希北现代字母', 键: 'xdi82xiandai', 读表: 解析制表符分隔文件, 是转出: false, 转出操作: 简易转出, 转入操作: 简易转入 },
	{ 名: '表情', 键: 'xdi82emoji', 读表: 解析制表符分隔文件, 是转出: false, 转出操作: 简易转出, 转入操作: 表情转入 },
	{ 名: '盲文', 键: 'xdi82mangwen', 读表: 解析制表符分隔文件, 是转出: false, 转出操作: 简易转出, 转入操作: 简易转入 },
	{ 名: '希伯来文', 键: 'xdi82hebrew', 读表: 解析制表符分隔文件, 是转出: false, 转出操作: 传统严格转出, 转入操作: 表情转入 },
	{ 名: '希北玛丽苏字母', 键: 'malisu2xdi8', 读表: 解析制表符分隔文件, 是转出: true, 转出操作: 简易转出, 转入操作: 简易转入 },
	{ 名: '字母汉字', 键: 'zmhz2xdi8', 读表: 解析制表符分隔文件, 是转出: true, 转出操作: 传统转出, 转入操作: 传统转入 }
];


window.onload = () => {
	var 从菜单 = document.getElementById('out');
	var 到菜单 = document.getElementById('in');

	function 获取字表(文字) {
		var 请求 = new XMLHttpRequest();
		请求.onreadystatechange = () => {
			if (请求.readyState == 4 && 请求.status == 200)
				文字.读表(请求.responseText);
		}
		请求.open('GET', '/xdi8/data/' + 文字.键 + '.tsv', true);
		请求.send();
	}

	function 添加菜单项(文字, 序号) {
		var 菜单项 = document.createElement('option');
		菜单项.text = 文字.名;
		菜单项.setAttribute('value', 序号.toString());
		if ('转出操作' in 文字)
			从菜单.add(菜单项, null);
		if ('转入操作' in 文字)
			到菜单.add(菜单项.cloneNode(true), null);
	}

	文字表.forEach((文字, 序号) => {
		if ('读表' in 文字) 获取字表(文字);
		添加菜单项(文字, 序号);
	});
};

var 可复制原始 = [];
var 可复制字串 = '';

function 重算可复制() {
	document.getElementById('copyable').value = 可复制字串 =
		可复制原始.map(段 => 段.join(' ')).join('\n');
}

function 生成振假名(x, 出文字, 入文字) {
	if (入文字 == 1)
		return '<span>' + x[1] + '</span><rp> (</rp><rt' + (出文字 ? '' : ' lang="art-x-xdi8"') + '>' + x[0] + '</rt><rp>) </rp>';
	else
		return '<span' + (出文字 ? '' : ' lang="art-x-xdi8"') + '>' + x[0] + '</span><rp>(</rp><rt' + (入文字 ? '' : ' lang="art-x-xdi8"') + '>' + x[1] + '</rt><rp>) </rp>';
}

function 生成响应(本词, 本段, 段序, 词序, 情况表, 出文字, 入文字) {
	return function 显示飘窗() {
		function 创建飘窗() {
			var 飘窗 = document.createElement('aside');
			飘窗.classList.add('zhxd-piao');
			飘窗.style.position = 'absolute';
			飘窗.style.left = 本词.offsetLeft + 'px';
			飘窗.style.top = (30 + 本词.offsetTop) + 'px';
			飘窗.onclick = 删除所有飘窗;
			var 关闭 = document.createElement('small');
			关闭.classList.add('zhxd-close');
			关闭.innerHTML = 'X 关闭';
			关闭.onclick = 删除所有飘窗;
			飘窗.appendChild(关闭);
			return 飘窗;
		}

		删除所有飘窗();
		飘窗 = 创建飘窗();
		情况表.forEach(function(情况) {
			var 本档 = document.createElement('p');
			var 别词 = document.createElement('ruby');
			情况.表.forEach(function(x) { 别词.innerHTML += 生成振假名(x, 出文字, 入文字); });
			本档.appendChild(别词);
			var 希顶写法 = document.createElement('span');
			希顶写法.lang = 'art-x-xdi8';
			希顶写法.innerHTML = ' (' + 情况.中 + ')';
			本档.appendChild(希顶写法);
			本档.onclick = function() {
				var 换词 = 别词.cloneNode(true);
				换词.classList.add('zhxd-fmt-modified');
				换词.onclick = 生成响应(换词, 本段, 段序, 词序, 情况表, 出文字, 入文字);
				本段.replaceChild(换词, 本词);
				可复制原始[段序][词序] = 情况.表.map(x => x[1]).join('');
				重算可复制();
			};
			飘窗.appendChild(本档);
		});
		document.getElementById('chained').appendChild(飘窗);
		var 最右 = document.getElementById('chained').offsetWidth - 飘窗.offsetWidth;
		if (最右 < 本词.offsetLeft)
			飘窗.style.left = 最右 + 'px';
	}
}

function 生成单情况显示表(中间情况, 目标情况) {
	var 显示表 = [];
	for (var i出 = 0, i入 = 0,
	     出长 = 0, 入长 = 0, 出句 = '', 入句 = ''; ; ) {
		if (出长 < 入长) {
			出长 += 中间情况[i出][1].length;
			出句 += 中间情况[i出++][0];
		} else {
			if (出长 == 入长 && 出长) {
				显示表.push([ 出句, 入句 ]);
				出句 = '';
				入句 = '';
			}
			if (i入 < 目标情况.length) {
				入长 += 目标情况[i入][0].length;
				入句 += 目标情况[i入++][1];
			}
			else break;
		}
	}
	return 显示表;
}

function 走你部分(出文字, 入文字, 框内原文) {
	可复制原始 = [];
	框内原文.split('\n').forEach(function(段, 段序) {
		可复制原始.push([]);
		var 本段 = document.createElement('p');
		段.split(' ').forEach(function(词, 词序) {
			var 情况表 = [];
			var 本词 = document.createElement('ruby');
			文字表[出文字].转出操作(词).forEach(function(中间情况) {
				var 中间词 = 中间情况.map(x => x[1]).join('');
				文字表[入文字].转入操作(中间词).forEach(function(目标情况) {
					var 显示表 = 生成单情况显示表(中间情况, 目标情况);
					情况表.push({ 中: 中间词, 表: 显示表 });
				}); 
			});
			if (!情况表.length) {
				本词.classList.add('zhxd-fmt-fail');
				情况表.push({ 中: null, 表: [ [ 词, 词 ] ] });
			}
			情况表.sort(function(u, v) {
				return u.表.length - v.表.length;
			});
			可复制原始[段序].push(情况表[0].表.map(x => x[1]).join(''));
			情况表[0].表.forEach(function(x) { 本词.innerHTML += 生成振假名(x, 出文字, 入文字); });
			本段.appendChild(本词);

			if (情况表.length != 1) {
				本词.classList.add('zhxd-fmt-multi');
				本词.onclick = 生成响应(本词, 本段, 段序, 词序, 情况表, 出文字, 入文字);
			}
		});
		document.getElementById('chained').appendChild(本段);
	});
	重算可复制();
}

function 走你() {
	var 出选单 = document.getElementById('out');
	var 入选单 = document.getElementById('in');
	var 入文字 = parseInt(入选单.options[入选单.selectedIndex].value);
	var 出文字 = parseInt(出选单.options[出选单.selectedIndex].value);
	if (出文字 == 入文字 && !出文字) { alert('请选择文字。'); return; }
	document.getElementById('chained').innerHTML = '';

	var 框内原文 = document.getElementById('zhxd-input').value;

	if (document.getElementById('jiakong-kongzhi').checked) {
		框内原文 = 框内原文.replace(
			new RegExp('(' + document.getElementById('jiakong').value + ')', 'g'),
			'$1 '
		);
	}

	if (document.getElementById('chinese-segment').checked) {
		var 请求 = new XMLHttpRequest();
		请求.open('POST', 'https://api.tianapi.com/txapi/nlpwords/index', true);
		请求.setRequestHeader("Content-type", "application/x-www-form-urlencoded");
		请求.send('key=' + document.getElementById('seg-key').value + '&str=1&content=' + 框内原文);
		请求.onreadystatechange = function () {
			if (请求.readyState == 4 && 请求.status == 200) {
				var 返回 = JSON.parse(请求.responseText);
				if ('success' != 返回.msg) alert('分词失败！'); 
				else 框内原文 = 返回.newslist[0].word.replace(/\n /g, '\n');
				走你部分(出文字, 入文字, 框内原文);
			}
		};
	} else {
		走你部分(出文字, 入文字, 框内原文);
	}
}

function 起风了() {
	document.getElementById('zhxd-input').value = [
		"这 一 路 上 走走-停停",
		"顺着 少年 漂流 的 痕迹",
		"迈出 车站 的 前 一 刻 竟 有些 犹豫",
		"不禁 笑 这 近乡-情怯 仍 无可 避免",
		"而 长野 的 天 依旧 那么 暖",
		"风 吹起了 从前",
		"从前 初识 这 世间 万般 流连",
		"看着 天边 似 在 眼前",
		"也 甘愿 赴汤-蹈火 去 走 它 一 遍",
		"如今 走过 这 世间 万般 流连",
		"翻过 岁月 不同 侧脸",
		"措不及防 闯入 你 的 笑颜",
		"我 曾 难 自拔 于 世界 之 大",
		"也 沉溺 于 其中 梦话",
		"不 得 真假 不 做 挣扎 不 惧 笑话",
		"我 曾 将 青春 翻涌 成 她",
		"也 曾 指尖 弹出 盛夏",
		"心 之 所 动 且 就 随缘 去 吧",
		"晚风 吹起 你 鬓 间 的 白发",
		"抚平 回忆 留下 的 疤",
		"你 的 眼 中 明-暗 交杂 一 笑 生 花",
		"暮色 遮住 你 蹒跚 的 步伐",
		"走进 床头 藏起 的 画",
		"画 中 的 你 低着 头 说话",
		"我 仍 感叹 于 世界 之 大",
		"也 沉醉 于 儿时 情话",
		"不 剩 真假 不 做 挣扎 无谓 笑话",
		"我 终 将 青春 还给了 她",
		"连同 指尖 弹出 的 盛夏",
		"心 之 所 动 就 随 风 去 了",
		"以 爱 之 名 你 还 愿意 吗"
	].join('\n');
}

const 剪贴板 = navigator.clipboard;

function 复制() {
	function 失败() {
		alert('抱歉，无法复制');
	}

	if (!剪贴板)
		失败();
	else
		剪贴板.writeText(可复制字串).then(null, 失败);
}

function 缓存() {
	if (!('serviceWorker' in navigator)) {
		alert('很抱歉，浏览器不支持 ServiceWorker！');
		return;
	}
	navigator.serviceWorker.register('/xdi8/sw.js', { scope: '/xdi8/' }).catch((误) => {
		alert('很抱歉，注册出错！\n' + 误);
	})
}
